home *** CD-ROM | disk | FTP | other *** search
/ PLAYymate for OS/2 / Playmate for OS2.iso / p4os2050 / taquin.c < prev    next >
C/C++ Source or Header  |  1989-02-27  |  12KB  |  292 lines

  1. /*---------------------------------------------------------
  2.    TAQUIN.C -- Jeu de Taquin for OS/2 Presentation Manager
  3.                (c) 1989, Ziff Communications Co.
  4.                PC Magazine * Charles Petzold, January 1989
  5.   ---------------------------------------------------------*/
  6.  
  7. #define INCL_WIN              // include 'Win' functions in OS/2 headers
  8. #define INCL_GPI              // include 'Gpi' functions in OS/2 headers
  9. #include <os2.h>
  10. #include <stdlib.h>
  11. #include "taquin.h"
  12.  
  13. #define NUMROWS        4      // greater than or equal to 2
  14. #define NUMCOLS        4      // greater than or equal to 3
  15. #define SCRAMBLEREP  100      // make larger if using more than 16 square
  16. #define SQUARESIZE    67      // in 1/100th inch
  17.  
  18. MRESULT EXPENTRY ClientWndProc (HWND, USHORT, MPARAM, MPARAM) ;
  19. MRESULT EXPENTRY AboutDlgProc  (HWND, USHORT, MPARAM, MPARAM) ;
  20.  
  21. int main (void)
  22.      {
  23.      static CHAR  szClientClass[] = "Taquin" ;
  24.      static ULONG flFrameFlags = FCF_SYSMENU  | FCF_TITLEBAR  |
  25.                                  FCF_BORDER   | FCF_MINBUTTON |
  26.                                  FCF_MENU     | FCF_ICON      |
  27.                                  FCF_TASKLIST ;
  28.      HAB          hab ;
  29.      HMQ          hmq ;
  30.      HWND         hwndFrame, hwndClient ;
  31.      QMSG         qmsg ;
  32.                               // Initialize and create standard window
  33.  
  34.      hab = WinInitialize (0) ;
  35.      hmq = WinCreateMsgQueue (hab, 0) ;
  36.      WinRegisterClass (hab, szClientClass, ClientWndProc, 0L, 0) ;
  37.      hwndFrame = WinCreateStdWindow (HWND_DESKTOP, WS_VISIBLE,
  38.                                      &flFrameFlags, szClientClass, NULL,
  39.                                      0L, NULL, ID_RESOURCE, &hwndClient) ;
  40.  
  41.                               // Get messages from queue and dispatch them
  42.  
  43.      while (WinGetMsg (hab, &qmsg, NULL, 0, 0))
  44.           WinDispatchMsg (hab, &qmsg) ;
  45.  
  46.                               // Clean up and terminate
  47.  
  48.      WinDestroyWindow (hwndFrame) ;
  49.      WinDestroyMsgQueue (hmq) ;
  50.      WinTerminate (hab) ;
  51.      return 0 ;
  52.      }
  53.  
  54. MRESULT EXPENTRY ClientWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  55.      {
  56.      static SHORT asPuzzle[NUMROWS][NUMCOLS],
  57.                   sBlankRow, sBlankCol, cxSquare, cySquare ;
  58.      CHAR         szNum[5] ;
  59.      HPS          hps ;
  60.      HWND         hwndFrame ;
  61.      POINTL       ptl ;
  62.      RECTL        rcl, rclInvalid, rclIntersect ;
  63.      SHORT        sRow, sCol, sMouseRow, sMouseCol, i ;
  64.      SIZEL        sizl ;
  65.  
  66.      switch (msg)
  67.           {
  68.           case WM_CREATE:
  69.                               // Calculate square size in pixels
  70.  
  71.                hps = WinGetPS (hwnd) ;
  72.                sizl.cx = sizl.cy = 0 ;
  73.                GpiSetPS (hps, &sizl, PU_LOENGLISH) ;
  74.                ptl.x = SQUARESIZE ;
  75.                ptl.y = SQUARESIZE ;
  76.                GpiConvert (hps, CVTC_PAGE, CVTC_DEVICE, 1L, &ptl) ;
  77.                WinReleasePS (hps) ;
  78.  
  79.                cxSquare = (SHORT) ptl.x ;
  80.                cySquare = (SHORT) ptl.y ;
  81.  
  82.                               // Calculate client window size and position
  83.  
  84.                rcl.xLeft   = (WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN) -
  85.                                            NUMCOLS * cxSquare) / 2 ;
  86.                rcl.yBottom = (WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN) -
  87.                                            NUMROWS * cySquare) / 2 ;
  88.                rcl.xRight  = rcl.xLeft   + NUMCOLS * cxSquare ;
  89.                rcl.yTop    = rcl.yBottom + NUMROWS * cySquare ;
  90.  
  91.                               // Set frame window position and size
  92.  
  93.                hwndFrame = WinQueryWindow (hwnd, QW_PARENT, FALSE) ;
  94.                WinCalcFrameRect (hwndFrame, &rcl, FALSE) ;
  95.                WinSetWindowPos  (hwndFrame, NULL,
  96.                                  (SHORT) rcl.xLeft, (SHORT) rcl.yBottom,
  97.                                  (SHORT) (rcl.xRight - rcl.xLeft),
  98.                                  (SHORT) (rcl.yTop - rcl.yBottom),
  99.                                  SWP_MOVE | SWP_SIZE | SWP_ACTIVATE) ;
  100.  
  101.                               // Initialize the asPuzzle array
  102.  
  103.                WinSendMsg (hwnd, WM_COMMAND, MPFROMSHORT (IDM_NORMAL), NULL) ;
  104.                return 0 ;
  105.  
  106.           case WM_PAINT:
  107.                hps = WinBeginPaint (hwnd, NULL, &rclInvalid) ;
  108.  
  109.                               // Draw the squares
  110.  
  111.                for (sRow = NUMROWS - 1 ; sRow >= 0 ; sRow--)
  112.                     for (sCol = 0 ; sCol < NUMCOLS ; sCol++)
  113.                          {
  114.                          rcl.xLeft   = cxSquare * sCol ;
  115.                          rcl.yBottom = cySquare * sRow ;
  116.                          rcl.xRight  = rcl.xLeft   + cxSquare ;
  117.                          rcl.yTop    = rcl.yBottom + cySquare ;
  118.  
  119.                          if (!WinIntersectRect (NULL, &rclIntersect,
  120.                                                 &rcl, &rclInvalid))
  121.                               continue ;
  122.  
  123.                          if (sRow == sBlankRow && sCol == sBlankCol)
  124.                               WinFillRect (hps, &rcl, CLR_BLACK) ;
  125.                          else
  126.                               {
  127.                               WinDrawBorder (hps, &rcl, 5, 5,
  128.                                              CLR_PALEGRAY, CLR_DARKGRAY,
  129.                                              DB_STANDARD | DB_INTERIOR) ;
  130.                               WinDrawBorder (hps, &rcl, 2, 2,
  131.                                              CLR_BLACK, 0L, DB_STANDARD) ;
  132.                               WinDrawText (hps, -1,
  133.                                       itoa (asPuzzle[sRow][sCol], szNum, 10),
  134.                                            &rcl, CLR_WHITE, CLR_DARKGRAY,
  135.                                            DT_CENTER | DT_VCENTER) ;
  136.                               }
  137.                          }
  138.                WinEndPaint (hps) ;
  139.                return 0 ;
  140.  
  141.           case WM_BUTTON1DOWN:
  142.                sMouseCol = MOUSEMSG(&msg)->x / cxSquare ;
  143.                sMouseRow = MOUSEMSG(&msg)->y / cySquare ;
  144.  
  145.                               // Check if mouse was in valid area
  146.  
  147.                if ( sMouseRow < 0          || sMouseCol < 0           ||
  148.                     sMouseRow >= NUMROWS   || sMouseCol >= NUMCOLS    ||
  149.                    (sMouseRow != sBlankRow && sMouseCol != sBlankCol) ||
  150.                    (sMouseRow == sBlankRow && sMouseCol == sBlankCol))
  151.                          break ;
  152.  
  153.                               // Move a row right or left
  154.  
  155.                if (sMouseRow == sBlankRow)
  156.                     {
  157.                     if (sMouseCol < sBlankCol)
  158.                          for (sCol = sBlankCol ; sCol > sMouseCol ; sCol--)
  159.                               asPuzzle[sBlankRow][sCol] =
  160.                                    asPuzzle[sBlankRow][sCol - 1] ;
  161.                     else
  162.                          for (sCol = sBlankCol ; sCol < sMouseCol ; sCol++)
  163.                               asPuzzle[sBlankRow][sCol] =
  164.                                    asPuzzle[sBlankRow][sCol + 1] ;
  165.                     }
  166.                               // Move a column up or down
  167.                else
  168.                     {
  169.                     if (sMouseRow < sBlankRow)
  170.                          for (sRow = sBlankRow ; sRow > sMouseRow ; sRow--)
  171.                               asPuzzle[sRow][sBlankCol] =
  172.                                    asPuzzle[sRow - 1][sBlankCol] ;
  173.                     else
  174.                          for (sRow = sBlankRow ; sRow < sMouseRow ; sRow++)
  175.                               asPuzzle[sRow][sBlankCol] =
  176.                                    asPuzzle[sRow + 1][sBlankCol] ;
  177.                     }
  178.                               // Calculate invalid rectangle
  179.  
  180.                rcl.xLeft   = cxSquare *  min (sMouseCol, sBlankCol) ;
  181.                rcl.yBottom = cySquare *  min (sMouseRow, sBlankRow) ;
  182.                rcl.xRight  = cxSquare * (max (sMouseCol, sBlankCol) + 1) ;
  183.                rcl.yTop    = cySquare * (max (sMouseRow, sBlankRow) + 1) ;
  184.  
  185.                               // Set new array and blank values
  186.  
  187.                sBlankRow = sMouseRow ;
  188.                sBlankCol = sMouseCol ;
  189.                asPuzzle[sBlankRow][sBlankCol] = 0 ;
  190.  
  191.                               // Invalidate rectangle
  192.  
  193.                WinInvalidateRect (hwnd, &rcl, FALSE) ;
  194.                break ;
  195.  
  196.           case WM_CHAR:
  197.                if (!(CHARMSG(&msg)->fs & KC_VIRTUALKEY) ||
  198.                      CHARMSG(&msg)->fs & KC_KEYUP)
  199.                          return 0 ;
  200.  
  201.                               // Mimic a WM_BUTTON1DOWN message
  202.  
  203.                sMouseCol = sBlankCol ;
  204.                sMouseRow = sBlankRow ;
  205.  
  206.                switch (CHARMSG(&msg)->vkey)
  207.                     {
  208.                     case VK_LEFT:   sMouseCol++ ;  break ;
  209.                     case VK_RIGHT:  sMouseCol-- ;  break ;
  210.                     case VK_UP:     sMouseRow-- ;  break ;
  211.                     case VK_DOWN:   sMouseRow++ ;  break ;
  212.                     default:        return 0 ;
  213.                     }
  214.                WinSendMsg (hwnd, WM_BUTTON1DOWN,
  215.                            MPFROM2SHORT (sMouseCol * cxSquare,
  216.                                          sMouseRow * cySquare), NULL) ;
  217.                return 0 ;
  218.  
  219.           case WM_COMMAND:
  220.                switch (COMMANDMSG(&msg)->cmd)
  221.                     {
  222.                               // Initialize asPuzzle array
  223.  
  224.                     case IDM_NORMAL:
  225.                     case IDM_INVERT:
  226.                          for (sRow = 0 ; sRow < NUMROWS ; sRow++)
  227.                               for (sCol = 0 ; sCol < NUMCOLS ; sCol++)
  228.                                    asPuzzle[sRow][sCol] = sCol + 1 +
  229.                                         NUMCOLS * (NUMROWS - sRow - 1) ;
  230.  
  231.                          if (COMMANDMSG(&msg)->cmd == IDM_INVERT)
  232.                               {
  233.                               asPuzzle[0][NUMCOLS-2] = NUMCOLS * NUMROWS - 2 ;
  234.                               asPuzzle[0][NUMCOLS-3] = NUMCOLS * NUMROWS - 1 ;
  235.                               }
  236.                          asPuzzle[sBlankRow = 0][sBlankCol = NUMCOLS - 1] = 0 ;
  237.                          WinInvalidateRect (hwnd, NULL, FALSE) ;
  238.                          return 0 ;
  239.  
  240.                               // Randomly scramble the squares
  241.  
  242.                     case IDM_SCRAMBLE:
  243.                          WinSetPointer (HWND_DESKTOP, WinQuerySysPointer (
  244.                                         HWND_DESKTOP, SPTR_WAIT, FALSE)) ;
  245.  
  246.                          srand ((int) WinGetCurrentTime (NULL)) ;
  247.  
  248.                          for (i = 0 ; i < SCRAMBLEREP ; i++)
  249.                               {
  250.                               WinSendMsg (hwnd, WM_BUTTON1DOWN,
  251.                                    MPFROM2SHORT (rand() % NUMCOLS * cxSquare,
  252.                                         sBlankRow * cySquare), NULL) ;
  253.                               WinUpdateWindow (hwnd) ;
  254.  
  255.                               WinSendMsg (hwnd, WM_BUTTON1DOWN,
  256.                                    MPFROM2SHORT (sBlankCol * cxSquare,
  257.                                         rand() % NUMROWS * cySquare), NULL) ;
  258.                               WinUpdateWindow (hwnd) ;
  259.                               }
  260.                          WinSetPointer (HWND_DESKTOP, WinQuerySysPointer (
  261.                                         HWND_DESKTOP, SPTR_ARROW, FALSE));
  262.                          return 0 ;
  263.  
  264.                               // Display dialog box
  265.  
  266.                     case IDM_ABOUT:
  267.                          WinDlgBox (HWND_DESKTOP, hwnd, AboutDlgProc,
  268.                                     NULL, IDD_ABOUT, NULL) ;
  269.                          return 0 ;
  270.                     }
  271.                break ;
  272.           }
  273.      return WinDefWindowProc (hwnd, msg, mp1, mp2) ;
  274.      }
  275.  
  276. MRESULT EXPENTRY AboutDlgProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  277.      {
  278.      switch (msg)
  279.           {
  280.           case WM_COMMAND:
  281.                switch (COMMANDMSG(&msg)->cmd)
  282.                     {
  283.                     case DID_OK:
  284.                     case DID_CANCEL:
  285.                          WinDismissDlg (hwnd, TRUE) ;
  286.                          return 0 ;
  287.                     }
  288.                break ;
  289.           }
  290.      return WinDefDlgProc (hwnd, msg, mp1, mp2) ;
  291.      }
  292.